6778. Равные множества сумм

 

Рассмотрим множество натуральных чисел, меньших или равных n. Отметим, что все элементы множества различны. Порядок элементов в множестве не существенен, то есть {3, 5, 9} и {5, 9, 3} являются одинаковыми множествами.

Количество элементов во множестве и их сумму будем обозначать через k и s соответственно. Количество множеств, удовлетворяющих этому условию, конечно. Если  n = 9, k = 3 и s = 23, то множество {6, 8, 9} будет единственным. Однако в общем случае множеств может быть и несколько. Если n = 9, k = 3 и s = 22, то оба из множеств {5, 8, 9} и {6, 7, 9} возможны.

Напишите программу, которая найдет количество множеств с заданными условиями.

 

Вход. Состоит из нескольких тестов, число которых не превышает 100.

Каждый тест состоит из одной строки, содержащей три целых числа n, k и s (1 ≤ n ≤ 20, 1 ≤ k ≤ 10 и 1 ≤ s ≤ 155).

Последняя строка содержит три нуля.

 

Выход. Для каждого теста вывести одно число - количество множеств с заданными условиями. Никаких лишних символов выводить не следует.

Считайте, что количество искомых множеств не превышает 231 – 1.

 

Пример входа

Пример выхода

9 3 23

9 3 22

10 3 28

16 10 107

20 8 102

20 10 105

20 10 155

3 4 3

4 2 11

0 0 0

1

2

0

20

1542

5448

1

0

0

 

 

РЕШЕНИЕ

комбинаторика - перебор

 

Анализ алгоритма

Сгенерируем массив m, в котором nk нулей  и k единиц. Причем единицы находятся в конце: m = (0, 0, …, 0, 1, 1, …, 1). Длина массива m равна n. Рассмотрим массив m как маску для множества (1, 2, 3,…, n).

Рассмотрим все перестановки множества m. Таким образом мы переберем все кортежи длины k из чисел (1, 2, 3,…, n). Причем кортежи будут содержать разные числа. Подсчитаем количество кортежей, которые будут иметь сумму s.

 

Реализация алгоритма

Читаем входные данные.

 

while (scanf("%d %d %d", &n, &k, &s), n + k + s)

{

 

Сгенерируем массив m = (0, 0, …, 0, 1, 1, …, 1).

 

  memset(m, 0, sizeof(m));

  for (i = n - 1; i >= n - k; i--) m[i] = 1;

 

Перебираем все кортежи длины k из чисел (1, 2, 3,…, n). Количество кортежей с суммой s подсчитываем в переменной res.

 

  res = 0;

  do

  {

 

Находим сумму sum подмножества чисел (1, 2, 3,…, n), которому соответствует маска m.

 

    sum = 0;

    for (i = 0; i < n; i++)

      if (m[i] == 1) sum += i + 1;

 

Если сумма равна s, то увеличиваем res на 1.

 

    if (sum == s) res++;

  } while (next_permutation(m, m + n));

 

Для текущего теста выводим ответ.

 

  printf("%d\n", res);

}